package com.newfiber.business.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.newfiber.business.constant.BusinessConstants;
import com.newfiber.business.domain.PatrolCase;
import com.newfiber.business.domain.PatrolLog;
import com.newfiber.business.domain.PatrolTask;
import com.newfiber.business.domain.request.patrolCase.PatrolCaseDeprecateRequest;
import com.newfiber.business.domain.request.patrolCase.PatrolCaseGeneratorNameRequest;
import com.newfiber.business.domain.request.patrolCase.PatrolCaseQueryCacheRequest;
import com.newfiber.business.domain.request.patrolCase.PatrolCaseQueryMyRequest;
import com.newfiber.business.domain.request.patrolCase.PatrolCaseQueryRequest;
import com.newfiber.business.domain.request.patrolCase.PatrolCaseSaveRequest;
import com.newfiber.business.domain.request.patrolCase.PatrolCaseSubmitRequest;
import com.newfiber.business.domain.request.patrolCase.PatrolCaseUpdateRequest;
import com.newfiber.business.enums.EPatrolCaseDataSource;
import com.newfiber.business.enums.EPatrolCaseStatus;
import com.newfiber.business.enums.EPatrolRedisKey;
import com.newfiber.business.enums.EWorkflowDefinition;
import com.newfiber.business.mapper.PatrolCaseMapper;
import com.newfiber.business.mapper.PatrolTaskMapper;
import com.newfiber.business.service.IPatrolCaseService;
import com.newfiber.business.service.IPatrolLogService;
import com.newfiber.common.core.context.SecurityContextHolder;
import com.newfiber.common.core.enums.EBoolean;
import com.newfiber.common.core.enums.EDelFag;
import com.newfiber.common.core.exception.ServiceException;
import com.newfiber.common.core.web.domain.BaseEntity;
import com.newfiber.common.core.web.service.BaseServiceImpl;
import com.newfiber.common.redis.service.RedisService;
import com.newfiber.common.security.utils.DictUtils;
import com.newfiber.common.security.utils.SecurityUtils;
import com.newfiber.system.api.RemoteFileService;
import com.newfiber.workflow.enums.EConstantValue;
import com.newfiber.workflow.service.FlowableProcessService;
import com.newfiber.workflow.support.IWorkflowCallback;
import com.newfiber.workflow.support.IWorkflowDefinition;
import com.newfiber.workflow.support.page.WorkflowPageHelper;
import com.newfiber.workflow.support.request.WorkflowStartRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import javax.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 巡查案件Service业务层处理
 *
 * @author X.K
 * @date 2023-02-17
 */
@Service
public class PatrolCaseServiceImpl extends BaseServiceImpl<PatrolCaseMapper, PatrolCase> implements IPatrolCaseService, IWorkflowCallback<PatrolCase> {

    @Resource
    private PatrolCaseMapper patrolCaseMapper;

    @Resource
    private PatrolTaskMapper patrolTaskMapper;

    @Resource
    private FlowableProcessService flowableProcessService;

    @Resource
    private IPatrolLogService patrolLogService;

    @Resource
    private RedisService redisService;

    @Resource
    private RemoteFileService remoteFileService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public long insert(PatrolCaseSaveRequest request) {
        PatrolCase patrolCase = wrapperPatrolCase(request);

        save(patrolCase);

        // 文件
        if (CollectionUtils.isNotEmpty(request.getFileSaveRequestList())) {
            remoteFileService.addBatch("patrolCase", patrolCase.getId(), request.getFileSaveRequestList());
        }

        // 启动工作流
        flowableProcessService.startWorkflow(this, patrolCase.getId(), request);

        // 案件数量 + 1
        patrolLogService.updateCaseCount(request.getPatrolLogId(), "+");

        return Optional.of(patrolCase).map(BaseEntity::getId).orElse(0L);
    }

    @Override
    public boolean insertCache(PatrolCaseSaveRequest request) {
        // 缓存巡查案件
        PatrolCase patrolCase = wrapperPatrolCase(request);
        String redisKey = String.format("%s:%s", request.getPatrolLogId(), DateUtil.current(true));
        redisService.setCacheObject(EPatrolRedisKey.PatrolCase, redisKey, JSONObject.toJSONString(patrolCase));

        return true;
    }

    @NotNull
    private PatrolCase wrapperPatrolCase(PatrolCaseSaveRequest request) {
        PatrolCase patrolCase = new PatrolCase();
        BeanUtils.copyProperties(request, patrolCase);
        patrolCase.setNumber(generatorNumber("PC", NumberFormat.DateSerialNumber));

        if (null != request.getPatrolLogId()) {
            PatrolLog patrolLog = patrolLogService.selectDetail(request.getPatrolLogId());
            patrolCase.setPatrolType(patrolLog.getPatrolType());
            patrolCase.setPatrolTaskId(patrolLog.getPatrolTaskId());
            patrolCase.setPatrolSectionId(patrolLog.getPatrolSectionId());
            if (null != patrolLog.getPatrolTaskId()) {
                PatrolTask patrolTask = patrolTaskMapper.selectOneById(patrolLog.getPatrolTaskId());
                patrolCase.setBasicInfoId(patrolTask.getBasicInfoId());
            }
        }
	    patrolCase.setDelFlag(EDelFag.NO.getCode());
	    patrolCase.setCreateTime(new Date());
        patrolCase.setCreateBy(SecurityUtils.getUsername());
        return patrolCase;
    }

    @Override
    public boolean update(PatrolCaseUpdateRequest request) {
        PatrolCase patrolCase = new PatrolCase();
        BeanUtils.copyProperties(request, patrolCase);
        return updateById(patrolCase);
    }

    @Override
    public boolean startCachedCaseByLog(Long patrolLogId) {
        List<String> patrolCaseStringList = redisService.mGet(EPatrolRedisKey.PatrolCase, patrolLogId.toString());
        if (CollectionUtils.isEmpty(patrolCaseStringList)) {
            return true;
        }

        PatrolLog patrolLog = patrolLogService.selectDetail(patrolLogId);
        String currentUser = patrolLog.getLogUserId().toString();
        for (String patrolCaseStr : patrolCaseStringList) {
            PatrolCase patrolCase = JSONObject.parseObject(patrolCaseStr, PatrolCase.class);

	        patrolCaseMapper.insert(patrolCase);

            // 案件数量 + 1
            patrolLogService.updateCaseCount(patrolLogId, "+");

            if (CollectionUtils.isNotEmpty(patrolCase.getFileSaveRequestList())) {
                remoteFileService.addBatch("patrolCase", patrolCase.getId(), patrolCase.getFileSaveRequestList());
            }

            // 启动工作流
            WorkflowStartRequest request = new WorkflowStartRequest();
	        request.setSubmitUserId(currentUser);
            request.setNextTaskApproveUserId(currentUser);
            flowableProcessService.startWorkflow(this, patrolCase.getId(), request);

            submitReport(patrolCase.getId(), patrolCase.getReportFlag(), currentUser);
        }

        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String submit(PatrolCaseSubmitRequest request) {
        PatrolCase patrolCase = selectDetail(request.getId());
        if (EBoolean.True.getStringValue().equals(patrolCase.getDeprecateFlag())) {
            throw new ServiceException("案件已废弃，无法提交");
        }

        UpdateWrapper<PatrolCase> updateWrapper = new UpdateWrapper<PatrolCase>().
                set("update_by", SecurityContextHolder.getUserName()).
                set("update_time", new Date()).
                set(null != request.getExpectEndDate(), "expect_end_date", request.getExpectEndDate()).
                eq("id", request.getId());
        update(updateWrapper);

        if (CollectionUtils.isNotEmpty(request.getFileSaveRequestList())) {
            remoteFileService.addBatch("patrolCase", request.getId(), request.getFileSaveRequestList());
        }

        if (EBoolean.False.getBoolString().equals(request.getApproveResult()) && StringUtils.isBlank(request.getNextTaskApproveUserId())) {
            String nextTaskApproveUserId = flowableProcessService.getNextHistoricAssignee(getWorkflowDefinition().getWorkflowKey(), request.getId(),
                    patrolCase.getStatus(), EConstantValue.CommonRefuseConditionExpression.getValue());
            request.setNextTaskApproveUserId(nextTaskApproveUserId);
        }
        return flowableProcessService.submitWorkflow(this, request.getId(), request);
    }

    @Override
    public void submitReport(long id, String reportFlag, String currentUser) {
        // 是否上报
        PatrolCaseSubmitRequest submitRequest = new PatrolCaseSubmitRequest();
        submitRequest.setId(id);
        submitRequest.setSubmitUserId(currentUser);
        if (EBoolean.True.getStringValue().equals(reportFlag)) {
            submitRequest.setApproveResult(EBoolean.True.getBoolString());
        } else {
            submitRequest.setApproveResult(EBoolean.False.getBoolString());
        }
        submit(submitRequest);
    }

    @Override
    public boolean deprecate(PatrolCaseDeprecateRequest request) {
        PatrolCase patrolCase = selectDetail(request.getId());
        if (EBoolean.True.getStringValue().equals(patrolCase.getDeprecateFlag())) {
            throw new ServiceException("案件已废弃，无法重复废弃");
        }

        if (!EPatrolCaseStatus.StartCase.getCode().equals(patrolCase.getStatus())) {
            throw new ServiceException("案件未处于立案状态，无法废弃");
        }

        flowableProcessService.abortWorkflow(this, request.getId());

        UpdateWrapper<PatrolCase> updateWrapper = new UpdateWrapper<PatrolCase>().
                set("deprecate_flag", EBoolean.True.getStringValue()).
                set("deprecate_reason", request.getDeprecateReason()).
                eq("id", request.getId());
        return update(updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(String ids) {
        Arrays.asList(ids.split(",")).forEach(id -> {
            PatrolCase patrolCase = patrolCaseMapper.selectOneById(Long.valueOf(id));
            // 排除单独的案件，不需要更新日志表，任务或者日志里面录入的案件。
            if (patrolCase != null && !EPatrolCaseDataSource.Case.equals(patrolCase.getCaseDataSource())) {
                // 删除案件的同时，更新案件对应日志表 问题数量字段 案件数量 -1
                patrolLogService.updateCaseCount(patrolCase.getPatrolLogId(), "-");
            }
        });
        return deleteLogic(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteCaseByTaskId(Long taskId) {
        QueryWrapper<PatrolCase> patrolCaseWrapper = new QueryWrapper<PatrolCase>().
                eq(BusinessConstants.PATROL_TASK_ID, taskId);
        return remove(patrolCaseWrapper);
    }

    @Override
    public long count(List<Long> taskIdList) {
        if (CollectionUtils.isEmpty(taskIdList)) {
            return 0L;
        }

        QueryWrapper<PatrolCase> patrolCaseWrapper = new QueryWrapper<PatrolCase>().
                in(BusinessConstants.PATROL_TASK_ID, taskIdList);
        return count(patrolCaseWrapper);
    }

    @Override
    public String generatorName(PatrolCaseGeneratorNameRequest request) {
        String caseTypeName = DictUtils.getDictCache("case_type", request.getCaseType());
        PatrolLog patrolLog = patrolLogService.selectDetail(request.getPatrolLogId());
        String caseNameFormat = "%s发现%s%s,问题等级:%s";
        return String.format(caseNameFormat, DateUtil.format(new Date(), "yyyy年MM月dd日"), patrolLog.getPatrolSectionName(), caseTypeName, request.getCaseLevel());
    }

    @Override
    public PatrolCase selectDetail(Long id) {
        PatrolCase patrolCase = patrolCaseMapper.selectOneById(id);
        if (null == patrolCase) {
            throw new ServiceException(String.format("%s ID=%s 的记录不存在", this.getClass().getSimpleName(), id));
        }
        return patrolCase;
    }

    @Override
    public List<PatrolCase> selectPage(PatrolCaseQueryRequest request) {
        return patrolCaseMapper.selectByCondition(request);
    }

    @Override
    public List<PatrolCase> selectPageMy(PatrolCaseQueryMyRequest request) {
        WorkflowPageHelper.startPage(request, this);
        return patrolCaseMapper.selectByCondition(request);
    }

    @Override
    public List<PatrolCase> myCase() {
        // 查询我的代办
//        PatrolCaseQueryMyRequest request = new PatrolCaseQueryMyRequest();
//        request.setQueryScope("todo");
//        request.setWorkflowUserId(SecurityUtils.getUserId().toString());
//        WorkflowPageHelper.startPage(request, this);
//        List<PatrolCase> patrolCases = patrolCaseMapper.selectByCondition(request);

        // 查询我创建的
        PatrolCaseQueryRequest patrolCaseQueryRequest = new PatrolCaseQueryRequest();
        patrolCaseQueryRequest.setCreateBy(SecurityUtils.getUsername());
        List<PatrolCase> patrolCases1 = patrolCaseMapper.selectByCondition(patrolCaseQueryRequest);
        return patrolCases1;
    }

    @Override
    public List<PatrolCase> selectList(PatrolCaseQueryRequest request) {
        return patrolCaseMapper.selectByCondition(request);
    }

    @Override
    public List<PatrolCase> selectListCache(PatrolCaseQueryCacheRequest request) {
        List<String> patrolCaseStringList = redisService.mGet(EPatrolRedisKey.PatrolCase, request.getPatrolLogId().toString());
        if (CollectionUtils.isEmpty(patrolCaseStringList)) {
            return Collections.emptyList();
        }

        List<PatrolCase> patrolCaseList = new ArrayList<>();
        for (String patrolCaseStr : patrolCaseStringList) {
            PatrolCase patrolCase = JSONObject.parseObject(patrolCaseStr, PatrolCase.class);
            patrolCaseList.add(patrolCase);
        }
        return patrolCaseList;
    }

    @Override
    public IWorkflowDefinition getWorkflowDefinition() {
        return EWorkflowDefinition.PatrolCase;
    }

    @Override
    public void refreshWorkflowInstanceId(Object businessKey, String workflowInstanceId) {
        UpdateWrapper<PatrolCase> updateWrapper = new UpdateWrapper<PatrolCase>().
                set("workflow_instance_id", workflowInstanceId).
                eq("id", businessKey);
        update(updateWrapper);
    }

    @Override
    public void refreshStatus(Object businessKey, String status) {
        UpdateWrapper<PatrolCase> updateWrapper = new UpdateWrapper<PatrolCase>().
                set("status", status).
                eq("id", businessKey);
        update(updateWrapper);
    }
}
